# 实现包的增量更新
import datetime
import json
from typing import Dict, Any

from globally import server_version, LocalDataRootPath
import os, requests, sys, copy
from lxml import html
import urllib.parse
from Class_Log import Log


class _LocalPackList:
    # 同过源地址repo_url获取对应本地存放路径
    @classmethod
    def _local_datapath(cls, repo_url):
        if not repo_url.endswith('/'):
            repo_url = repo_url + '/'
        local_datapath = LocalDataRootPath + '/'.join((repo_url+'Packages').split('/')[3:])
        if not os.path.exists(local_datapath):
            os.makedirs(local_datapath)
        return local_datapath

    # 通过repo_url获取对应本地路径所有包列表
    def local_packlist(self, repo_url):
        local_exist_packlist = []
        for root, dirname, filenames in os.walk(self._local_datapath(repo_url)):
            for mumber in filenames:
                if mumber.endswith(".rpm"):
                    local_exist_packlist.append(mumber)
        return local_exist_packlist


class _OnlinePackList:
    def online_packlist(self, repo_url):
        if not repo_url.endswith('/'):
            repo_url = repo_url + '/'
        url = repo_url + 'Packages'
        response = requests.get(url)
        if response.status_code == 200:
            html_content = response.text
            # soup = BeautifulSoup(html_content, 'html.parser')
            # html = soup.prettify()
        else:
            print("外网源访问错误")
            sys.exit(1)
        decoded_html = urllib.parse.unquote(html_content, encoding="UTF-8")
        online_exist_packlist = []
        # sys.exit(0)
        tree = html.fromstring(html_content)
        links = tree.xpath('//a/@href')
        for mumber in links:
            if mumber.endswith(".rpm"):
                online_exist_packlist.append(mumber.replace("%2B", "+"))
        # print(packlist)
        # print("外网源包总计：", len(packlist))
        return online_exist_packlist

# 创建任务书
class PlatForm_CreateAssignment(_LocalPackList, _OnlinePackList, Log):
    def create_assignments(self, version):
        self.LOG_Assisgnment(1, "\n****************************************\n  增量更新  版本：{} 时间：{}\n****************************************".format(version, datetime.datetime.now()))
    # ---- 获取对应version的所有任务书 ----
        assignment_list = self._assignment_list(version)
    # ---- 日志记录 ----
        for assignment in assignment_list:
            self.LOG_Assisgnment(1, '====> {}的任务书： {} <===='.format(version, assignment["repo_url"]))
            loginfo = ["    外网源地址：{}".format(assignment["repo_url"]),
                       "    内网源地址：{}".format(assignment["local_workpath"]),
                       "    {}".format(assignment["task_info"])]
            self.LOG_Assisgnment(1, loginfo)
            for mumber in assignment["task_downloadpacklist"]:
                self.LOG_Assisgnment(1, "        新增： {}".format(mumber))
            for mumber in assignment["task_removepacklist"]:
                self.LOG_Assisgnment(1, "        删除： {}".format(mumber))
        return assignment_list

    # 创建任务书，用来记录，软件包的增加于删除。 输入：系统版本 输出：任务书（list） —— 记录url、本地工作目录、任务细则
    def _assignment_list(self, version) -> json:
        # 生成每个源地址的任务书。
        global _assignment
        assignment_list = []
        for repo_url in server_version[version]:
        # ---- 前置准备工作 ----
            # 1、规范repo_url格式，以/结尾
            if not repo_url.endswith('/'):
                repo_url = repo_url + '/'
            # 2、创建对应repo_url的本地目录
            # local_workpath为repo_url对应本地的工作目录，和Packages，repodata的目录
            _local_workpath = LocalDataRootPath + '/'.join((repo_url).split('/')[2:])
            if not os.path.exists(_local_workpath):
                os.makedirs(_local_workpath)
        # ---- 任务书创建 ----
            _assignment = {"repo_url": repo_url,
                           "local_workpath": _local_workpath,
                           "task_info": "",
                           "task_removepacklist": "",
                           "task_downloadpacklist": ""}
            _assignment["task_info"], _assignment["task_removepacklist"], _assignment["task_downloadpacklist"] = self._pack_compare(_assignment["repo_url"])
        assignment_list.append(_assignment)
        return assignment_list


    # 内外网源包对比。
    @classmethod
    def _pack_compare(cls, repo_url: str) -> list:
        localpacks = _LocalPackList().local_packlist(repo_url)
        onlinepacks = _OnlinePackList().online_packlist(repo_url)
        localpackleave = copy.deepcopy(localpacks)
        onlinepackleave = copy.deepcopy(onlinepacks)
        for mumber in onlinepacks:
            if mumber in localpacks:
                localpackleave.remove(mumber)
                onlinepackleave.remove(mumber)
        # 生成结论
        result_info = "需要从外网源下载：{}个包，需要从内网源删除：{}个包".format(len(onlinepackleave), len(localpackleave))
        result_removelist = localpackleave
        result_downloadlist = onlinepackleave
        # for packname in localpackleave:
        #     re_pack = "- {}".format(packname)
        #     compare_result.append(re_pack)
        # for packname in onlinepackleave:
        #     re_pack = "+ {}".format(packname)
        #     compare_result.append(re_pack)
        return [result_info, result_removelist, result_downloadlist]


# 执行任务书
class PlatForm_PerformTask:
    def _remove(self, removelist):
        def _local_datapath(cls, repo_url):
            local_datapath = LocalDataRootPath + '/'.join((repo_url + 'Packages').split('/')[3:])
            if not os.path.exists(local_datapath):
                os.makedirs(local_datapath)
            return local_datapath

    def _download(self, downloadlist):
        pass

    @classmethod
    def perform_tasks(cls, assignment_lists):
        for assignment in assignment_lists:
        # ---- 拆分任务 ----
            removelist = []
            downloadlist = []
            for line in assignment["task_details"]:
                # 提取删除列表和下载列表
                if line.startswith('-'):
                    removelist.append(line.split(' ')[-1].lstrip().rstrip())
                if line.startswith('+'):
                    downloadlist.append(line.split(' ')[-1].lstrip().rstrip())
        # 分别执行删除任务和下载任务




